package com.echo.echovividlive.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.PageResult;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.echo.echovividlive.common.Constants;
import com.echo.echovividlive.common.UserThread;
import com.echo.echovividlive.domain.dto.FollowingVideosDTO;
import com.echo.echovividlive.domain.dto.PageQueryDTO;
import com.echo.echovividlive.domain.dto.VideoPageDTO;
import com.echo.echovividlive.domain.entity.Result;
import com.echo.echovividlive.domain.entity.User;
import com.echo.echovividlive.domain.entity.Video;
import com.echo.echovividlive.domain.vo.PageVO;
import com.echo.echovividlive.domain.vo.VideoVO;
import com.echo.echovividlive.mapper.UserMapper;
import com.echo.echovividlive.mapper.VideoMapper;
import com.echo.echovividlive.service.IVideoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.echo.echovividlive.utils.TimeUtil;
import com.echo.echovividlive.utils.VideoUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.RequiredArgsConstructor;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.echo.echovividlive.common.Constants.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xiajunjie
 * @since 2024-10-22
 */
@Service
@RequiredArgsConstructor
public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video> implements IVideoService {

    private final VideoMapper videoMapper;

    private final FileStorageService fileStorageService;

    private final UserMapper userMapper;

    private final StringRedisTemplate stringRedisTemplate;

    private final RabbitTemplate rabbitTemplate;

    @Value("${dromara.x-file-storage.minio[1].platform}")
    private String VIDEO_PLATFORM;

    @Value("${dromara.x-file-storage.minio[0].end-point}")
    private String MINIO_OBS_URL;

    @Override
    public Result upload(MultipartFile video) throws FileNotFoundException {
        if (video == null || video.isEmpty()) {
            return Result.error("请选择需要发布的视频");
        }
        if (!VideoUtil.isVideo(video)) {
            return Result.error("请上传视频文件");
        }
        User user = userMapper.selectById(UserThread.getUserId());
        // 上传视频
        long begin = System.currentTimeMillis();
        FileInfo upload = fileStorageService
                .of(video)
                .setPlatform(VIDEO_PLATFORM)
                .upload();
        String cover = "";
        // 创建缓存文件，用于存储缩略图
        File tempFile = FileUtil.createTempFile('.'+Constants.VIDEO_INDEX_IMAGE_TYPE,true);
        OutputStream outputStream = new FileOutputStream(tempFile);
        try {
            // 获取视频封面并上传
            VideoUtil.getVideoImage(video,outputStream);
            FileInfo img = fileStorageService
                    .of(tempFile)
                    .setPlatform(VIDEO_PLATFORM)
                    .upload();
            cover = MINIO_OBS_URL + VIDEO_BUCKET + img.getUrl();
            outputStream.close();
            FileUtil.del(tempFile);
        }catch (Exception e){
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("上传视频总耗时"+((end-begin)/1000)   +"s");
        // 构造video实体返回前端
        Video build = Video.builder()
                .commentCount(0)
                .goodCount(0L)
                .url(MINIO_OBS_URL+ VIDEO_BUCKET + upload.getUrl())
                .status(VIDEO_STATUS_ON)
                .cover(cover)
                .userId(UserThread.getUserId())
                .build();
        // 删除缓存文件
        return Result.success(build);
    }

    @Override
    public Result post(Video video) {
        if (video == null || StrUtil.isBlank(video.getUrl())) {
            return Result.error("视频不见了");
        }
        video.setCreateTime(TimeUtil.getCurrentTime());
        if (this.save(video)) {
            return Result.success();
        }
        return Result.error("发布失败");
    }

    @Override
    @Transactional
    public Result delete(Video video) {
        if (video == null || StrUtil.isBlank(video.getUrl())) {
            return Result.error("视频不见了");
        }
        // 删除视频信息
        this.removeById(video.getVideoId());
        // 异步删除文件信息
        rabbitTemplate.convertAndSend(VIDEO_DELETE_QUEUE, JSONObject.toJSONString(video));
        return Result.success();
    }

    @Override
    public Result pageList(VideoPageDTO pageQueryDTO) {
        PageHelper.startPage(pageQueryDTO.getPageIndex()==null?1:pageQueryDTO.getPageIndex(),
                pageQueryDTO.getPageSize()==null?10:pageQueryDTO.getPageSize());
        Page<VideoVO> videos = videoMapper.pageList(pageQueryDTO);
        return Result.success(new PageVO(videos.getTotal(),videos.getResult()));
    }

    @Override
    public Result getVideo(Integer videoId) {
        Integer userId = UserThread.getUserId();
        Video video = videoMapper.selectOne(new LambdaQueryWrapper<Video>()
                .eq(Video::getVideoId, videoId)
                .eq(Video::getStatus,VIDEO_STATUS_ON));
        VideoVO videoVO = new VideoVO();
        BeanUtil.copyProperties(video,videoVO);
        User postUser = userMapper.selectById(video.getUserId());
        videoVO.setAvatar(postUser.getAvatar());
        videoVO.setNickName(postUser.getNickName());
        videoVO.setFansCount(postUser.getFansCount());
        if (userId==null){
            return Result.success(videoVO);
        }
        // 判断用户是否点赞过该视频
        Long index = stringRedisTemplate.opsForList().indexOf(USER_LIKE_KEY + userId, videoId.toString());
        videoVO.setIsLiked(index != null);
        return Result.success(videoVO);
    }

    @Override
    public Result getFollowingVideos(FollowingVideosDTO followingVideosDTO) {
        // 获取当前用户的关注列表
        List<String> range = stringRedisTemplate.opsForList().range(USER_FOLLOWING_KEY + UserThread.getUserId(), 0, -1);
        List<Integer> collect = range.stream().map(Integer::parseInt).collect(Collectors.toList());
        if(collect.isEmpty()){
            return Result.success(new PageVO(0L, ListUtil.empty()) );
        }
        followingVideosDTO.setFollowingUserIds(collect);
        PageHelper.startPage(followingVideosDTO.getPageIndex()==null?1:followingVideosDTO.getPageIndex(),
                followingVideosDTO.getPageSize()==null?10:followingVideosDTO.getPageSize());
        Page<VideoVO> videoVOS = videoMapper.pageListByUserIds(followingVideosDTO);
        return Result.success(new PageVO(videoVOS.getTotal(),videoVOS.getResult()));
    }

    @Override
    public Result isVideoLike(Integer videoId) {
        Integer userId = UserThread.getUserId();
        Long index = stringRedisTemplate.opsForList().indexOf(USER_LIKE_KEY + userId, videoId.toString());
        return Result.success(index!=null);
    }

    @Override
    public Result getLikedVideos(VideoPageDTO pageQueryDTO) {
        Integer userId = UserThread.getUserId();
        List<String> range = stringRedisTemplate.opsForList().range(USER_LIKE_KEY + userId, 0, -1);
        List<Integer> videoIds = range.stream().map(Integer::parseInt).collect(Collectors.toList());
        if(videoIds.isEmpty()){
            return Result.success(new PageVO(0L, ListUtil.empty()) );
        }
        PageHelper.startPage(pageQueryDTO.getPageIndex(),pageQueryDTO.getPageSize());
        Page<VideoVO> videoVOS =  videoMapper.selectLikedVideos(videoIds);
        return Result.success(new PageVO(videoVOS.getTotal(),videoVOS.getResult()));
    }

    @Override
    public Result uploadCover(MultipartFile cover) {
        FileInfo upload = fileStorageService.of(cover)
                .setPlatform(VIDEO_PLATFORM)
                .upload();
        return Result.success(MINIO_OBS_URL+ VIDEO_BUCKET + upload.getUrl());
    }
}
